#!/usr/bin/php -q
<?php
use Phalcon\Cli\Task;

$short_opts = 't:a:p:h'; // t - task
                         // a - action
                         // p - parameters
                         // h - help
$options = getopt($short_opts);

$HELP =
<<<HELP
usage: php galera-cluster-check.php [OPTION]... [PARAMS]...
    -h show help message
    -t specify task
    -a specify action
    -p parameter(s) passed to action, eg: host=127.0.0.1&user=root&pasword=p455w0rd

:)


HELP;

if (isset($options['h'])) {
	echo $HELP;
	exit(0);
}

$args = [];

if (!isset($options['t'])) {
	error_log('Please specify the task you want to run with -t');
	exit(1);
}
if (!isset($options['a'])) {
	error_log('Please specify the action you want to run with -a');
	exit(1);
}

$args['task']   = $options['t'];
$args['action'] = $options['a'];

if (isset($options['p'])) {
	mb_parse_str($options['p'], $params);
	$args['params'] = $params;
}

/**
 * This makes our life easier when dealing with paths.
 * Everything is relative to the application root now.
 */
chdir(dirname(__DIR__));

$di = new Phalcon\DI();

$di->setShared('router', function() { return new Phalcon\Cli\Router(); });
$di->setShared('dispatcher', function() { return new Phalcon\Cli\Dispatcher(); });

$cli = new Phalcon\Cli\Console();
$cli->setDI($di);

try {
	$cli->handle($args);
}
catch (\Phalcon\Exception $e) {
	echo "HTTP/1.1 500 Server Internal Error\r\n";
	echo "Content-Type: text/plain\r\n";
	echo "Connection: close\r\n";
	echo "Content-Length: 7\r\n\r\n";
	echo "ERROR";
	exit(1);
}

class MainTask extends Task
{
	private function send($status, $content)
	{
		$length = mb_strlen($content);
		$pattern = "%s\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: %d\r\n\r\n%s\r\n";
		echo sprintf($pattern, $status, $length, $content);
	}
	
	public function checkAction(array $params)
	{
		if (file_exists('/var/tmp/gc.disabled')) {
			$this->send('HTTP/1.1 503 Service Unavailable', 'DISABLED');
			exit(1);
		}
		
		$host      = $params['host'] ?? '127.0.0.1';   // server-ip-address
		$port      = $params['port'] ?? 3306;          // service-port
		$user      = $params['user'] ?? 'root';        // user
		$password  = $params['password'] ?? '';        // password
		$eod       = $params['enable-on-donor'] ?? 1;  // enable-on-donor
		$ignore_ro = $params['ignore-read-only'] ?? 1; // ignore-read-only
		$ignore_rl = $params['ignore-lagging'] ?? 1;   // ignore-replication-lagging
		
		$connection = new PDO("mysql:host={$host};dbname=information_schema;port={$port}", $user, $password);
		$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		$connection->exec('set names utf8mb4;');
		$sql =
<<<SQL
		SELECT VARIABLE_NAME,VARIABLE_VALUE FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME IN ('read_only', 'wsrep_provider_options', 'wsrep_slave_threads')
		UNION
		SELECT VARIABLE_NAME,VARIABLE_VALUE FROM GLOBAL_STATUS WHERE VARIABLE_NAME IN ('wsrep_local_state', 'wsrep_local_recv_queue');
SQL;
		$stmt = $connection->query($sql);
		$rows = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
		$connection = null;
		
		if (array_key_exists('WSREP_LOCAL_STATE', $rows) && array_key_exists('WSREP_LOCAL_RECV_QUEUE', $rows)) {
			if ($rows['WSREP_LOCAL_STATE'] == 4 || $rows['WSREP_LOCAL_STATE'] == 2 && $eod == 1) {
				/*
				 * Check only when set to 0 to avoid latency in response
				 */
				if ($ignore_ro == 0) {
					if ($rows['READ_ONLY'] == 'ON') {
						$this->send('HTTP/1.1 503 Service Unavailable', 'READ_ONLY');
						exit(1);
					}
				}

				/*
				 * Check to see if the node's receive queue has filled up to the threshold
				 * The threshold in this case is gcs.fc_limit
				 */
				if ($ignore_rl == 0) {
					$pattern = '/gcs.fc_limit\s*=\s*(\d+?);/';
					preg_match_all($pattern, $rows['WSREP_PROVIDER_OPTIONS'], $matches);
					$fc_limit = intval($matches[1][0]);
					if ($rows['WSREP_LOCAL_RECV_QUEUE'] > $fc_limit - $rows['WSREP_SLAVE_THREADS']) {
						$this->send('HTTP/1.1 503 Service Unavailable', 'LAGGING');
						exit(1);
					}
				}
				$this->send('HTTP/1.1 200 OK', 'SYNCED');
				exit(0);
			}
			else {
				if ($rows['WSREP_LOCAL_STATE'] == 2) {
					$this->send('HTTP/1.1 503 Service Unavailable', 'RUNAS_DONOR');
				}
				else {
					$this->send('HTTP/1.1 503 Service Unavailable', 'OUT_OF_SYNC');
				}
				exit(1);
			}
		}
		/*
		 *  Cannot retrieve galera cluster status from the server
		 */
		else {
			$this->send('HTTP/1.1 503 Service Unavailable', 'NOT_RUNNING');
			exit(1);
		}
	}
}
